package com.sunday.common.core.utils;

import com.sunday.common.core.constants.StringConstants;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Map;
import java.util.stream.Stream;

/**
 * 利用反射重写toString
 *
 * @author zsy
 * @since 2022/10/11
 */
@Slf4j
public class ReflectToStringUtils {

    public static String toString(Object obj) {
        return toString(obj, true, true, false);
    }

    public static String toString(Object obj, boolean isOutputFinal) {
        return toString(obj, true, true, isOutputFinal);
    }

    public static String toString(Object obj, boolean isOutputNull, boolean isArrToSize, boolean isOutputFinal) {
        StringBuffer sb = new StringBuffer();
        getParamAndValue(obj, obj.getClass(), isOutputNull, isArrToSize, isOutputFinal, sb);
        if (sb.length() > 0) {
            sb.replace(sb.length() - 1, sb.length(), StringConstants.EMPTY);
        }
        return sb.toString();
    }

    /**
     * 递归参数与值 打印公共log信息
     *
     * @param obj           toString 对象
     * @param clazz         泛型
     * @param isOutputNull  是否开启null值打印  等于true的时候输出 null值参数
     * @param isArrToSize   是否开启集合转size  等于true的时候输出 size长度，不打印详细内容
     * @param isOutputFinal 是否开启final打印   等于true的时候输出
     * @param sb
     */
    private static void getParamAndValue(Object obj, Class<?> clazz, boolean isOutputNull, boolean isArrToSize, boolean isOutputFinal, StringBuffer sb) {

        Class<?> superClass = clazz.getSuperclass();
        Field[] superFields = superClass.getDeclaredFields();
        if (superFields.length > 0) {
            getParamAndValue(obj, superClass, isOutputNull, isArrToSize, isOutputFinal, sb);
        }
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true);
            try {
                Object value = field.get(obj);
                if (isOutputNull || value != null) {                                  // null
                    if (Modifier.isFinal(field.getModifiers()) && !isOutputFinal) {   // final 或 不开启静态参数输出
                        continue;
                    }
                    if (Modifier.isTransient(field.getModifiers())) {                // transient
                        continue;
                    }
                    if (Modifier.isStatic(field.getModifiers())) {                   // static
                        continue;
                    }
                    //【强制】判断所有集合内部的元素是否为空，使用 isEmpty()方法，而不是 size()==0 的方式。
                    // 说明：在某些集合中，前者的时间复杂度为 O(1)，而且可读性更好。
                    if (value instanceof Collection coll && !coll.isEmpty() && isArrToSize) {
                        sb.append(field.getName()).append(StringConstants.COLON).append(coll.size()).append(StringConstants.COMMA);
                        continue;
                    }
                    if (value instanceof Map map && !map.isEmpty() && isArrToSize) {
                        sb.append(field.getName()).append(StringConstants.COLON).append(map.size()).append(StringConstants.COMMA);
                        continue;
                    }
                    if (value != null && value.getClass().isArray()) {
                        if (isArrToSize) {
                            sb.append(field.getName()).append(StringConstants.COLON).append(Array.getLength(value)).append(StringConstants.COMMA);
                        } else {
                            sb.append(field.getName()).append(StringConstants.COLON).append(Stream.iterate(0, i -> i < Array.getLength(value), i -> i + 1).map(i -> Array.get(value, i)).toList()).append(StringConstants.COMMA);
                        }
                        continue;
                    }
                    sb.append(field.getName()).append(StringConstants.COLON).append(value).append(StringConstants.COMMA);
                }
            } catch (Exception e) {
                log.error("reflect to string error : {}", e.toString(), e);
            }
        }
    }

}
